/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.layoutlib.bridge.bars;

import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.layoutlib.bridge.resources.IconLoader;
import com.android.layoutlib.bridge.resources.SysUiResources;
import com.android.resources.Density;
import com.android.resources.LayoutDirection;
import com.android.resources.ResourceType;

import android.annotation.NonNull;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.io.IOException;
import java.io.InputStream;

import static android.os._Original_Build.VERSION_CODES.LOLLIPOP;

/**
 * Base "bar" class for the window decor around the the edited layout.
 * This is basically an horizontal layout that loads a given layout on creation (it is read
 * through {@link Class#getResourceAsStream(String)}).
 * <p>
 * The given layout should be a merge layout so that all the children belong to this class directly.
 * <p>
 * It also provides a few utility methods to configure the content of the layout.
 */
abstract class CustomBar extends LinearLayout {
    private final int mSimulatedPlatformVersion;

    protected CustomBar(BridgeContext context, int orientation, String layoutName,
            int simulatedPlatformVersion) {
        super(context);
        mSimulatedPlatformVersion = simulatedPlatformVersion;
        setOrientation(orientation);
        if (orientation == LinearLayout.HORIZONTAL) {
            setGravity(Gravity.CENTER_VERTICAL);
        } else {
            setGravity(Gravity.CENTER_HORIZONTAL);
        }

        LayoutInflater inflater = LayoutInflater.from(mContext);
        BridgeXmlBlockParser bridgeParser = loadXml(layoutName);
        try {
            inflater.inflate(bridgeParser, this, true);
        } finally {
            bridgeParser.ensurePopped();
        }
    }

    protected abstract TextView getStyleableTextView();

    protected BridgeXmlBlockParser loadXml(String layoutName) {
        return SysUiResources.loadXml((BridgeContext) mContext, mSimulatedPlatformVersion,
                layoutName);
    }

    protected ImageView loadIcon(ImageView imageView, String iconName, Density density) {
        return SysUiResources.loadIcon(mContext, mSimulatedPlatformVersion, imageView, iconName,
                density, false);
    }

    protected ImageView loadIcon(int index, String iconName, Density density, boolean isRtl) {
        View child = getChildAt(index);
        if (child instanceof ImageView) {
            ImageView imageView = (ImageView) child;
            return SysUiResources.loadIcon(mContext, mSimulatedPlatformVersion, imageView, iconName,
                    density, isRtl);
        }

        return null;
    }

    protected ImageView loadIcon(ImageView imageView, String iconName, Density density,
            boolean isRtl) {
        LayoutDirection dir = isRtl ? LayoutDirection.RTL : null;
        IconLoader iconLoader = new IconLoader(iconName, density, mSimulatedPlatformVersion, dir);
        InputStream stream = iconLoader.getIcon();

        if (stream != null) {
            density = iconLoader.getDensity();
            String path = iconLoader.getPath();
            // look for a cached bitmap
            Bitmap bitmap = Bridge.getCachedBitmap(path, Boolean.TRUE /*isFramework*/);
            if (bitmap == null) {
                try {
                    bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
                    Bridge.setCachedBitmap(path, bitmap, Boolean.TRUE /*isFramework*/);
                } catch (IOException e) {
                    return imageView;
                }
            }

            if (bitmap != null) {
                BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(), bitmap);
                imageView.setImageDrawable(drawable);
            }
        }

        return imageView;
    }

    protected TextView setText(int index, String string) {
        View child = getChildAt(index);
        if (child instanceof TextView) {
            TextView textView = (TextView) child;
            textView.setText(string);
            return textView;
        }

        return null;
    }

    protected void setStyle(String themeEntryName) {
        BridgeContext bridgeContext = getContext();
        RenderResources res = bridgeContext.getRenderResources();

        ResourceValue value =
                res.findItemInTheme(BridgeContext.createFrameworkAttrReference(themeEntryName));
        value = res.resolveResValue(value);

        if (!(value instanceof StyleResourceValue)) {
            return;
        }

        StyleResourceValue style = (StyleResourceValue) value;

        // get the background
        ResourceValue backgroundValue = res.findItemInStyle(style,
                BridgeContext.createFrameworkAttrReference("background"));
        backgroundValue = res.resolveResValue(backgroundValue);
        if (backgroundValue != null) {
            Drawable d = ResourceHelper.getDrawable(backgroundValue, bridgeContext);
            if (d != null) {
                setBackground(d);
            }
        }

        TextView textView = getStyleableTextView();
        if (textView != null) {
            // get the text style
            ResourceValue textStyleValue = res.findItemInStyle(style,
                    BridgeContext.createFrameworkAttrReference("titleTextStyle"));
            textStyleValue = res.resolveResValue(textStyleValue);
            if (textStyleValue instanceof StyleResourceValue) {
                StyleResourceValue textStyle = (StyleResourceValue) textStyleValue;

                ResourceValue textSize = res.findItemInStyle(textStyle,
                        BridgeContext.createFrameworkAttrReference("textSize"));
                textSize = res.resolveResValue(textSize);

                if (textSize != null) {
                    TypedValue out = new TypedValue();
                    if (ResourceHelper.parseFloatAttribute("textSize", textSize.getValue(), out,
                            true /*requireUnit*/)) {
                        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                                out.getDimension(bridgeContext.getResources().getDisplayMetrics()));
                    }
                }

                ResourceValue textColor = res.findItemInStyle(textStyle,
                        BridgeContext.createFrameworkAttrReference("textColor"));
                textColor = res.resolveResValue(textColor);
                if (textColor != null) {
                    ColorStateList stateList =
                            ResourceHelper.getColorStateList(textColor, bridgeContext, null);
                    if (stateList != null) {
                        textView.setTextColor(stateList);
                    }
                }
            }
        }
    }

    @Override
    public BridgeContext getContext() {
        return (BridgeContext) mContext;
    }

    /**
     * Find the background color for this bar from the theme attributes. Only relevant to StatusBar
     * and NavigationBar.
     * <p/>
     * Returns 0 if not found.
     *
     * @param colorAttrName the attribute name for the background color
     * @param translucentAttrName the attribute name for the translucency property of the bar.
     *
     * @throws NumberFormatException if color resolved to an invalid string.
     */
    protected int getBarColor(@NonNull String colorAttrName, @NonNull String translucentAttrName) {
        if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) {
            return 0;
        }
        RenderResources renderResources = getContext().getRenderResources();
        // First check if the bar is translucent.
        boolean translucent = ResourceHelper.getBooleanThemeFrameworkAttrValue(renderResources,
                translucentAttrName, false);
        if (translucent) {
            // Keep in sync with R.color.system_bar_background_semi_transparent from system ui.
            return 0x66000000;  // 40% black.
        }
        boolean transparent = ResourceHelper.getBooleanThemeFrameworkAttrValue(renderResources,
                "windowDrawsSystemBarBackgrounds", false);
        if (transparent) {
            return getColor(renderResources, colorAttrName);
        }
        return 0;
    }

    private static int getColor(RenderResources renderResources, String attr) {
        // From ?attr/foo to @color/bar. This is most likely an StyleItemResourceValue.
        ResourceValue resource =
                renderResources.findItemInTheme(BridgeContext.createFrameworkAttrReference(attr));
        // Form @color/bar to the #AARRGGBB
        resource = renderResources.resolveResValue(resource);
        if (resource != null) {
            ResourceType type = resource.getResourceType();
            if (type == null || type == ResourceType.COLOR) {
                // if no type is specified, the value may have been specified directly in the style
                // file, rather than referencing a color resource value.
                try {
                    return ResourceHelper.getColor(resource.getValue());
                } catch (NumberFormatException e) {
                    // Conversion failed.
                    Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                            "Theme attribute @android:" + attr +
                                    " does not reference a color, instead is '" +
                                    resource.getValue() + "'.", resource);
                }
            }
        }
        return 0;
    }
}
